package cn.com.wxd.common.file;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.Iterator;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MatrixToImageWriter;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;

/**
 * Title:图片修改工具类
 * Description:
 * <p>
 * Company: Amumu管理平台
 * Copyright: Copyright (c) 2015
 * All right reserved.
 * Created time: 2016-4-26 下午12:00:05
 *
 * @author WangXuDong
 * @version 1.0
 */
public class ImageUtil {
    private static final Logger log = LoggerFactory.getLogger(ImageUtil.class);
    private Image img;
    private String extName;
    private File inFile;

    /**
     * 实例化图片修改工具类
     *
     * @param filePath图片地址
     *
     * @throws IOException IO异常
     */
    public ImageUtil(String filePath) throws IOException {
        inFile = new File(filePath); // 读入文件
        extName = filePath.substring(filePath.lastIndexOf(".") + 1);
        inFile.getName();
        img = ImageIO.read(inFile); // 构造Image对象
    }

    /**
     * 判断输出的文件地址是否正确
     *
     * @param outFilePath
     *
     * @return
     */
    private boolean isExtNameOfoutFile(String outFilePath) {
        if (extName.equalsIgnoreCase(outFilePath.substring(outFilePath.lastIndexOf(".")))) {
            return true;
        }
        return false;
    }

    /**
     * 缩放图片
     *
     * @param w           宽
     * @param h           高
     * @param outFilePath 输出文件名称 如 D://a.jpg
     *
     * @throws IOException
     */
    public void resize(int w, int h, String outFilePath) throws IOException {
        if (isExtNameOfoutFile(outFilePath)) {
            log.error("输出的文件类型和修改的的文件类型不一致!");
            return;
        }
        BufferedImage _image = new BufferedImage(w, h,
                BufferedImage.TYPE_INT_RGB);
        _image.getGraphics().drawImage(img, 0, 0, w, h, null); // 绘制缩小后的图
        //FileOutputStream newimageout = new FileOutputStream(outPath); // 输出到文件流
        /*
		 * JPEGImageEncoder 将图像缓冲数据编码为 JPEG 数据流。该接口的用户应在 Raster 或 
		 * BufferedImage 中提供图像数据，在 JPEGEncodeParams 对象中设置必要的参数， 并成功地打开 
		 * OutputStream（编码 JPEG 流的目的流）。JPEGImageEncoder 接口可 将图像数据编码为互换的缩略 
		 * JPEG 数据流，该数据流将写入提供给编码器的 OutputStream 中。 
		 * 注意：com.sun.image.codec.jpeg 包中的类并不属于核心 Java API。它们属于 Sun 发布的 JDK 
		 * 和 JRE 产品的组成部分。虽然其它获得许可方可能选择发布这些类，但开发人员不能寄 希望于从非 Sun 
		 * 实现的软件中得到它们。我们期望相同的功能最终可以在核心 API 或标准扩 展中得到。 
		 */
        //JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(newimageout);
        //encoder.encode(_image); // 近JPEG编码
        //获取文件的后缀
        File outFile = new File(outFilePath);
        if (outFile.isDirectory()) {
            log.error("outFilePath不能为目录", new IOException("outFilePath 不能为目录"));
        }
        ImageIO.write(_image, extName, outFile);
        // 比如  ImageIO.write(img,"jpeg",new File("D:/1.jpg"));
    }

    /**
     * 添加图片水印
     *
     * @param outFilePath 输出的图片路径
     * @param waterImg    水印图片路径，如：C:\\kutuku.png
     * @param x           水印图片距离目标图片左侧的偏移量，如果x<0, 则在正中间
     * @param y           水印图片距离目标图片上侧的偏移量，如果y<0, 则在正中间
     * @param alpha       透明度(0.0 -- 1.0, 0.0为完全透明，1.0为完全不透明)
     *
     * @throws IOException
     */
    public void addWaterMark(String outFilePath, String waterImg, int x, int y, float alpha) throws IOException {
        if (isExtNameOfoutFile(outFilePath)) {
            log.error("输出的文件类型和修改的的文件类型不一致!");
            return;
        }
        // 加载目标图片
        File file = inFile;
        File outfile = new File(outFilePath);
        String ext = outFilePath.substring(outFilePath.lastIndexOf(".") + 1);
        Image image = ImageIO.read(file);
        int width = image.getWidth(null);
        int height = image.getHeight(null);

        // 将目标图片加载到内存。
        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = bufferedImage.createGraphics();
        g.drawImage(image, 0, 0, width, height, null);

        // 加载水印图片。
        Image waterImage = ImageIO.read(new File(waterImg));
        int width_1 = waterImage.getWidth(null);
        int height_1 = waterImage.getHeight(null);
        // 设置水印图片的透明度。
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));

        // 设置水印图片的位置。
        int widthDiff = width - width_1;
        int heightDiff = height - height_1;
        if (x < 0) {
            x = widthDiff / 2;
        } else if (x > widthDiff) {
            x = widthDiff;
        }
        if (y < 0) {
            y = heightDiff / 2;
        } else if (y > heightDiff) {
            y = heightDiff;
        }

        // 将水印图片“画”在原有的图片的制定位置。
        g.drawImage(waterImage, x, y, width_1, height_1, null);
        // 关闭画笔。
        g.dispose();
        try {
            // 保存目标图片。
            ImageIO.write(bufferedImage, ext, outfile);
        } catch (IOException e) {
            log.error("ImageIO 输出错误。" + e.getMessage(), e);
        }

    }

    /**
     * 生成图片二维码
     *
     * @param content     文字内容
     * @param width
     * @param height
     * @param extenName   图片扩展名 如 png jpg
     * @param outFilePath 输出地址 包含文件名称和扩展名
     *
     * @throws WriterException 输出异常
     * @throws IOException     文件异常
     */
    public void gener2DbarCode(String content, int width, int height, String outFilePath) throws WriterException,
            IOException {
        if (isExtNameOfoutFile(outFilePath)) {
            log.error("输出的文件类型和修改的的文件类型不一致!");
            return;
        }
        if (width <= 0 || height <= 0 || content == null
                || content.isEmpty() || outFilePath == null || outFilePath.isEmpty()) {
            return;
        }
        String extenName = outFilePath.substring(outFilePath.lastIndexOf(".") + 1, outFilePath.length());
        if (extenName.isEmpty()) {
            return;
        }
        Hashtable hints = new Hashtable();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
        File outputFile = new File(outFilePath);
        MatrixToImageWriter.writeToFile(bitMatrix, extenName, outputFile);
    }

    /**
     * 生成文字图片
     *
     * @param content     内容
     * @param outFilePath 输出图片文件地址
     * @param width
     * @param height
     * @param font        字体，为null 默认是"黑体", Font.BOLD, 25
     * @param fontColor   默认是黑色
     * @param backColor   默认是白色
     */
    public void generTextPic(String content, String outFilePath, int width, int height, Font font, Color fontColor,
                             Color backColor) {
        if (isExtNameOfoutFile(outFilePath)) {
            log.error("输出的文件类型和修改的的文件类型不一致!");
            return;
        }
        if (width <= 0 || height <= 0 || outFilePath == null || outFilePath.isEmpty() || content == null || content
                .isEmpty()) {
            return;
        }
        if (outFilePath.lastIndexOf(".") < 0) {
            return;
        }
        String ext = outFilePath.substring(outFilePath.lastIndexOf(".") + 1);
        File file = new File(outFilePath);
        BufferedImage bi = new BufferedImage(width, height,
                BufferedImage.TYPE_INT_RGB);

        Graphics2D g2 = (Graphics2D) bi.getGraphics();
        if (backColor == null) {
            backColor = Color.WHITE;
        }
        g2.setBackground(backColor);
        g2.clearRect(0, 0, width, height);

        if (font == null) {
            font = new Font("黑体", Font.BOLD, 25);
        }
        if (fontColor == null) {
            fontColor = Color.black;
        }
        g2.setFont(font);
        g2.setPaint(fontColor);
        FontRenderContext context = g2.getFontRenderContext();
        Rectangle2D bounds = font.getStringBounds(content, context);
        double x = (width - bounds.getWidth()) / 2;
        double y = (height - bounds.getHeight()) / 2;
        double ascent = -bounds.getY();
        double baseY = y + ascent;

        g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

        g2.drawString(content, (int) x, (int) baseY);

        try {
            ImageIO.write(bi, ext, file);
        } catch (IOException e) {
            log.error("ImageIo输出图片出现错误" + e.getMessage(), e);
        }
    }

    /**
     * 根据图片路径生成缩略图
     *
     * @param w           缩略图宽
     * @param h           缩略图高
     * @param outFilePath 存放缩略图的地址
     * @param force       是否强制按照宽高生成缩略图(如果为false，则生成最佳比例缩略图)
     */
    public void thumbnailImage(int w, int h, String outFilePath, boolean force) {
        if (isExtNameOfoutFile(outFilePath)) {
            log.error("输出的文件类型和修改的的文件类型不一致!");
            return;
        }
        File imgFile = inFile;
        if (imgFile.exists()) {
            try {
                // ImageIO 支持的图片类型 : [BMP, bmp, jpg, JPG, wbmp, jpeg, png, PNG, JPEG, WBMP, GIF, gif]
                String types = Arrays.toString(ImageIO.getReaderFormatNames());
                String suffix = null;
                // 获取图片后缀
                if (imgFile.getName().indexOf(".") > -1) {
                    suffix = imgFile.getName().substring(imgFile.getName().lastIndexOf(".") + 1);
                }// 类型和图片后缀全部小写，然后判断后缀是否合法
                if (suffix == null || types.toLowerCase().indexOf(suffix.toLowerCase()) < 0) {
                    if (log.isErrorEnabled()) {
                        log.error("Sorry, the image suffix is illegal. the standard image suffix is {}." + types);
                    }
                    return;
                }
                log.debug("target image's size, width:" + w + ", height:" + h + ".");
                Image img = ImageIO.read(imgFile);
                if (!force) {
                    // 根据原图与要求的缩略图比例，找到最合适的缩略图比例
                    int width = img.getWidth(null);
                    int height = img.getHeight(null);
                    if ((width * 1.0) / w < (height * 1.0) / h) {
                        if (width > w) {
                            h = Integer.parseInt(new java.text.DecimalFormat("0").format(height * w / (width * 1.0)));
                            log.debug("change image's height, width:" + w + ", height:" + h + ".");
                        }
                    } else {
                        if (height > h) {
                            w = Integer.parseInt(new java.text.DecimalFormat("0").format(width * h / (height * 1.0)));
                            log.debug("change image's width, width:" + w + ", height:" + h + ".");
                        }
                    }
                }
                BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
                Graphics g = bi.getGraphics();
                g.drawImage(img, 0, 0, w, h, Color.LIGHT_GRAY, null);
                g.dispose();
                ImageIO.write(bi, suffix, new File(outFilePath));
            } catch (IOException e) {
                log.error("generate thumbnail image failed." + e.getMessage(), e);
            }
        } else {
            log.error("图片文件不存在。");
        }
    }

    /**
     * 根据原图与裁切size截取局部图片
     *
     * @param outFilePath 输出图片的地址
     * @param x
     * @param y
     * @param width
     * @param height
     */
    public void cutImage(String outFilePath, int x, int y, int width, int height) {
        if (isExtNameOfoutFile(outFilePath)) {
            log.error("输出的文件类型和修改的的文件类型不一致!");
            return;
        }
        Rectangle rect = new Rectangle(x, y, width, height);
        File srcImg = inFile;
        if (srcImg.exists()) {
            FileInputStream is = null;
            ImageInputStream iis = null;
            try {
                is = new FileInputStream(srcImg);
                Iterator<ImageReader> it = ImageIO.getImageReadersByFormatName(extName);
                ImageReader reader = it.next();
                iis = ImageIO.createImageInputStream(is);

                reader.setInput(iis, true);
                ImageReadParam param = reader.getDefaultReadParam();
                param.setSourceRegion(rect);
                BufferedImage bi = reader.read(0, param);
                ImageIO.write(bi, extName, new File(outFilePath));
            } catch (IOException e) {
                log.error("裁剪图片发生异常" + e.getMessage(), e);
            } finally {
                try {
                    if (is != null) {
                        is.close();
                    }
                    if (iis != null) {
                        iis.close();
                    }
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
        } else {
            log.error("the src image is not exist.");
        }
    }

}
